using System;
using System.Diagnostics.Contracts;

namespace OpenWaves.Caching
{
    [ContractClass(typeof(ConcurrentCacheContract<>))]
    public interface IConcurrentCache<T> : ICache<T> where T : class
    {
        T GetOrCreate(string key, Func<ConcurrentCacheEntry<T>> create);
    }


    public static class ConcurrentCacheExtensions
    {
        public static T GetOrCreate<T>(this IConcurrentCache<T> cache, string key, Func<CacheEntry<T>> create) where T : class
        {
            return cache.GetOrCreate(key, () =>
                {
                    var entry = create();
                    return new ConcurrentCacheEntry<T>(entry.Value, entry.AbsoluteExpiration);
                });
        }

        public static T GetOrCreate<T>(this IConcurrentCache<T> cache, string key, Func<T> create) where T : class
        {
            return cache.GetOrCreate(key, () =>
            {
                var entry = create();
                return new ConcurrentCacheEntry<T>(entry);
            });
        }
    }


    [ContractClassFor(typeof(IConcurrentCache<>))]
    abstract class ConcurrentCacheContract<T> : IConcurrentCache<T> where T : class
    {
        public T GetOrCreate(string key, Func<ConcurrentCacheEntry<T>> create)
        {
            Contract.Requires<ArgumentNullException>(String.IsNullOrEmpty(key) == false);
            Contract.Requires<ArgumentNullException>(create != null);
            Contract.Ensures(Contract.Result<T>() != null);

            throw new NotImplementedException();
        }

        public void InsertValue(string key, T value, DateTime absoluteExpiration)
        {
            throw new NotImplementedException();
        }

        public void EvictValue(string key)
        {
            throw new NotImplementedException();
        }

        public T GetValue(string key)
        {
            throw new NotImplementedException();
        }
    }
}